package com.project.poetry.service.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.project.poetry.common.constant.ConstantValue;
import com.project.poetry.common.constant.DictConstant;
import com.project.poetry.common.exception.ServiceException;
import com.project.poetry.common.util.CommonUtil;
import com.project.poetry.service.entity.dto.flyingflower.FlyingFlowerAnswerDTO;
import com.project.poetry.service.entity.dto.flyingflower.FlyingFlowerDTO;
import com.project.poetry.service.entity.dto.flyingflower.FlyingFlowerDetailDTO;
import com.project.poetry.service.entity.dto.flyingflower.FlyingFlowerRankingDTO;
import com.project.poetry.service.entity.po.flyingflower.FlyingFlowerLogPO;
import com.project.poetry.service.entity.po.flyingflower.FlyingFlowerPO;
import com.project.poetry.service.entity.po.user.UserPO;
import com.project.poetry.service.mapper.FlyingFlowerLogMapper;
import com.project.poetry.service.mapper.FlyingFlowerMapper;
import com.project.poetry.service.service.FlyingFlowerService;
import com.project.poetry.service.service.PoetryService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 飞花令业务层实现类
 * @author mengxj
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class FlyingFlowerServiceImpl implements FlyingFlowerService {

    @Resource
    private PoetryService poetryService;

    @Resource
    private FlyingFlowerMapper flyingFlowerMapper;

    @Resource
    private FlyingFlowerLogMapper flyingFlowerLogMapper;

    private static final Map<String, List<String>> CACHE_FLYING_FLOWER = new HashMap<>();

    private static final Map<String, List<String>> HAS_SHOW = new HashMap<>();

    @Override
    @Transactional(noRollbackFor = ServiceException.class, rollbackFor = Exception.class)
    public FlyingFlowerDTO getContentByKeyWord(String keyWord, Long flyingId, UserPO user) {
        CommonUtil.checkThrow(CommonUtil :: checkChinese, keyWord,
                ConstantValue.SERVICE_DATA_ERROR_STATUS_CODE, String.format("关键字必须全是中文：%s 不符合规范！！！", keyWord));
        List<String> hasShow = this.getHasShowList(user);
        if(flyingId.equals(-1L)){
            hasShow.clear();
        }
        List<String> list = this.getContentListByKeyWord(keyWord);
        list.removeAll(hasShow);
        if(CommonUtil.isEmpty(list)){
            FlyingFlowerPO flyingFlower = this.flyingFlowerMapper.selectById(flyingId);
            flyingFlower.setVictory(DictConstant.TRUE);
            this.flyingFlowerMapper.updateById(flyingFlower);
            this.finish(flyingId, user);
            throw new ServiceException(ConstantValue.NOT_HAVE_ENABLE_CONTENT, "牛！你胜了，系统无可用诗句！");
        }
        int index = (int)Math.floor(Math.random() * list.size());
        String answer = list.get(index);
        flyingId = this.saveFlyingFlower(flyingId, keyWord, answer, user);
        return FlyingFlowerDTO.builder().answer(answer).flyingId(flyingId).build();
    }

    private List<String> getContentListByKeyWord(String keyWord){
        List<String> list = CACHE_FLYING_FLOWER.get(keyWord);
        if(CommonUtil.isEmpty(list)){
            list = this.poetryService.getContentListByKeyWord(keyWord);
        }
        CommonUtil.checkThrow(CommonUtil :: isEmpty, list,
                ConstantValue.SERVICE_DATA_ERROR_STATUS_CODE, String.format("该关键字：%s 无对应诗句，请换一个关键字。", keyWord));
        CACHE_FLYING_FLOWER.put(keyWord, list);
        return new ArrayList<>(list);
    }

    @Override
    public void saveFlyingFlowerAnswer(FlyingFlowerAnswerDTO flyingFlowerAnswer, UserPO user) {
        String loginId = user.getLoginId();
        String content = flyingFlowerAnswer.getAnswer(), keyWord = flyingFlowerAnswer.getKeyWord();
        CommonUtil.checkThrow(l -> {
                    for(String con : l){
                        if(content.contains(con) || con.contains(content)){
                            return true;
                        }
                    }
                    return false;
                }, HAS_SHOW.get(loginId),
                ConstantValue.SERVICE_DATA_ERROR_STATUS_CODE, String.format("诗句：%s 出现过！！！", content));
        CommonUtil.checkThrow(s -> !s.contains(keyWord), content,
                ConstantValue.SERVICE_DATA_ERROR_STATUS_CODE, String.format("输入的诗句：%s 不包含关键字：%s", content, keyWord));
        this.saveFlyingFlower(flyingFlowerAnswer.getFlyingId(), keyWord, content, user);
    }

    private Long saveFlyingFlower(Long flyingId, String keyWord, String content, UserPO user){
        Long userId = user.getId();
        this.addHasShow(user.getLoginId(), keyWord, content);
        FlyingFlowerPO flyingFlower = this.flyingFlowerMapper.selectById(flyingId);
        String nowDateString = CommonUtil.nowDateTimeString();
        if(Objects.isNull(flyingFlower)){
            flyingFlower = new FlyingFlowerPO();
            flyingFlower.setKeyWord(keyWord);
            flyingFlower.setUserId(userId);
            flyingFlower.setStartTime(nowDateString);
            this.flyingFlowerMapper.insert(flyingFlower);
        }
        flyingId = flyingFlower.getId();
        FlyingFlowerLogPO flyingFlowerLog = new FlyingFlowerLogPO();
        flyingFlowerLog.setFlyingId(flyingId);
        flyingFlowerLog.setUserId(userId);
        flyingFlowerLog.setAnswer(content);
        this.flyingFlowerLogMapper.insert(flyingFlowerLog);
        return flyingId;
    }

    private void addHasShow(String loginId, String keyWord, String content){
        List<String> showList = HAS_SHOW.get(loginId);
        showList.add(content);
        List<String> hasList = CACHE_FLYING_FLOWER.get(keyWord);
        hasList.forEach(con -> {
            if(con.contains(content) || content.contains(con)){
                showList.add(con);
            }
        });
    }

    @Override
    public void finish(Long flyingId, UserPO user) {
        this.getHasShowList(user).clear();
        this.updateFlyingFlower(flyingId, 1);
    }

    @Override
    public List<FlyingFlowerPO> flyingFlowerHistory(String keyWord, Integer status, UserPO user) {
        QueryWrapper<FlyingFlowerPO> wrapper = new QueryWrapper<>();
        CommonUtil.eq(wrapper, "user_id", user.getId());
        CommonUtil.like(wrapper, "key_word", keyWord);
        if(status == 1){
            wrapper.last(" and end_time is not null order by start_time desc");
        }else if(status == 2){
            wrapper.last(" and end_time is null and time is not null order by start_time desc");
        }else if(status == 3) {
            wrapper.last(" and end_time is null and time is null order by start_time desc");
        }else{
            wrapper.last(" order by start_time desc");
        }
        return this.flyingFlowerMapper.selectList(wrapper);
    }

    @Override
    public List<FlyingFlowerDetailDTO> flyingFlowerDetail(Long flyingId) {
        return this.flyingFlowerMapper.flyingFlowerDetail(flyingId);
    }

    @Override
    public List<FlyingFlowerRankingDTO> ranking(Integer num) {
        List<FlyingFlowerRankingDTO> list = this.flyingFlowerMapper.ranking(num);
        int score = 0, no = 1, cache = 1;
        for(FlyingFlowerRankingDTO dto : list){
            int sc = dto.getScore();
            dto.setNo(no);
            if(sc < score){
                no += cache;
                score = sc;
            }else{
                cache += 1;
            }
        }
        return list;
    }

    @Override
    public FlyingFlowerPO continueFlyingFlower(Long flyingId, UserPO user){
        FlyingFlowerPO flyingFlower = this.flyingFlowerMapper.selectById(flyingId);
        List<FlyingFlowerLogPO> logList = this.flyingFlowerLogMapper.selectList(
                new QueryWrapper<FlyingFlowerLogPO>().lambda().eq(FlyingFlowerLogPO :: getFlyingId, flyingId));
        List<String> hasShowList = this.getHasShowList(user);
        hasShowList.addAll(
                logList.stream().map(FlyingFlowerLogPO::getAnswer).collect(Collectors.toList()));
        this.getContentListByKeyWord(flyingFlower.getKeyWord());
        return flyingFlower;
    }

    @Override
    public void updateFlyingFlower(Long flyingId, int flag){
        FlyingFlowerPO flyingFlower = this.flyingFlowerMapper.selectById(flyingId);
        List<FlyingFlowerLogPO> logList = this.flyingFlowerLogMapper.selectList(
                new QueryWrapper<FlyingFlowerLogPO>().lambda().eq(FlyingFlowerLogPO :: getFlyingId, flyingId));
        int time = logList.size() / 2;
        flyingFlower.setTime(time);
        flyingFlower.setScore(time * 2);
        if(flag == 1){
            Integer victory;
            flyingFlower.setVictory(Objects.isNull(victory = flyingFlower.getVictory()) ? DictConstant.FALSE : victory);
            flyingFlower.setEndTime(CommonUtil.nowDateTimeString());
        }
        this.flyingFlowerMapper.updateById(flyingFlower);
    }

    private List<String> getHasShowList(UserPO user){
        String loginId = user.getLoginId();
        List<String> hasShow = HAS_SHOW.get(loginId);
        if(Objects.isNull(hasShow)){
            hasShow = new ArrayList<>();
            HAS_SHOW.put(loginId, hasShow);
        }
        return hasShow;
    }
}
